﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.Web.Routing;


namespace System.Web.Mvc
{
    
    public static class HtmlHelperExtension
    {
        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="action">ActionName</param>
        /// <param name="controller">ControllerName</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        /// <param name="pageSizeName">每页大小的名称</param>
        /// <param name="sizes">每页大小选择</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string action, string controller, string pageName, RouteValueDictionary routeValues, string pageSizeName, IEnumerable<int> sizes)
        {
            StringBuilder sb1 = new StringBuilder();

            if (string.IsNullOrEmpty(pageName))
                pageName = "PageIndex";
            if (routeValues == null)
                routeValues = new RouteValueDictionary();
            if (!routeValues.ContainsKey(pageName))
                routeValues.Add(pageName, null);

            int currentPage = page ?? 1;
            int currentPageSize = size ?? defaultSize;
            if (currentPage < 1)
                currentPage = 1;
            if (currentPageSize < 1)
                currentPageSize = 15;

            var Pagerlength = 4;//当前页向两边扩展的长度
            var SumPageCount = (int)Math.Ceiling(totalRecords * 1.0 / currentPageSize);
            if (currentPage > SumPageCount)
                currentPage = SumPageCount;
            if (currentPage < 1)
                currentPage = 1;

            Func<int, string> url = p =>
            {
                var page1 = p;
                if (page1 < 1)
                    page1 = 1;
                else if (page1 > SumPageCount)
                    page1 = SumPageCount;
                routeValues[pageName] = page1;
                return UrlHelper.GenerateUrl(null, action, controller, routeValues, htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true);
            };
            Func<string,string> url1 = p =>
            {
                routeValues[pageName] = p;
                return UrlHelper.GenerateUrl(null, action, controller, routeValues, htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true);
            };

            if (totalRecords <= 0)
                return MvcHtmlString.Empty;
            if (string.IsNullOrEmpty(pageSizeName))
                sb1.AppendLine(string.Format("[<font color='red'>{0}/{1}</font>]&nbsp;&nbsp;[<font color='red'>{2}</font>]&nbsp;&nbsp;&nbsp;&nbsp;", currentPage, SumPageCount, currentPageSize));
            else
            {
                if (!routeValues.ContainsKey(pageSizeName))
                    routeValues.Add(pageSizeName, null);
                if(sizes==null)
                    sizes = new List<int>() {10,15,20,30 };
                if (!sizes.Contains(currentPageSize))
                    sizes = sizes.Union(new int[] { currentPageSize });
                var sizes1 = sizes.OrderBy(p=>p);
                sb1.AppendFormat("[<font color='red'>{0}/{1}</font>]&nbsp;&nbsp;[{2}]&nbsp;&nbsp;", currentPage, SumPageCount,
                    string.Join("\r\n", sizes.OrderBy(p => p).Select(p =>
                    {
                        routeValues[pageSizeName] = p; return string.Format("<a {0}>{1}</a>",
                            p != currentPageSize ? "href='"+UrlHelper.GenerateUrl(null, action, controller, routeValues, htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true)+"'" : "",
                            p != currentPageSize ? p.ToString() : "<font color='red'' style='font-weight:bold;'>" + p + "</font>");
                    }).ToArray()));
                routeValues[pageSizeName] = size;
            }
            

            if (currentPage - Pagerlength > 1)
            {
                sb1.AppendLine(string.Format("&nbsp;&nbsp;<a href='{0}' class='a_blue'>&lt;&lt;</a>", url(1)));
                sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>&lt;</a>", url(currentPage - 1)));
                sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>...</a>", url(currentPage - Pagerlength)));
            }else  if (currentPage > 1)
                sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>&lt;</a>", url(currentPage - 1)));
            
            for (int i = currentPage - Pagerlength; i <= SumPageCount && i <= currentPage + Pagerlength; i++)
            {
                if (i <= 0)
                    i = 1;
                if (i == currentPage)
                    sb1.AppendLine(string.Format("&nbsp;&nbsp;<font color='red' style='font-weight:bold;'>{0}</font>", i));
                else
                    sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>{1}</a>", url(i), i));
            }

            bool flag = false;
            if (currentPage + Pagerlength < (SumPageCount - 1))
            {
                sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>...</a>", url(currentPage + Pagerlength)));
                flag = true;
            }

            if (currentPage <= (SumPageCount - 1))
                sb1.AppendLine(String.Format("&nbsp;&nbsp;<a href=\"{0}\" class='a_blue'>&gt;</a>", url(currentPage + 1)));

            if (flag)
            {
                sb1.AppendLine(string.Format("&nbsp;&nbsp;<a href='{0}' class='a_blue'>&gt;&gt;</a>", url(SumPageCount)));
            }
            if(SumPageCount>Pagerlength)
                sb1.AppendLine("&nbsp;&nbsp;<input id='txtGoPage' style='width:15px'/> <a href='' class='a_blue' onclick=\"javascript:var page=document.getElementById('txtGoPage');if(page.value==''){this.href='" + url(currentPage + 1) + "';}else{if(page.value<1){page.value=1;}else if(page.value>" + SumPageCount + "){page.value=" + SumPageCount + ";}this.href='" + url1("'+page.value+'").Replace("%2B", "+") + "';}\">Go</a>");
            return MvcHtmlString.Create(sb1.ToString());
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="action">ActionName</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        /// <param name="pageSizeName">每页大小的名称</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string action, string pageName, RouteValueDictionary routeValues, string pageSizeName)
        {
            return htmlHelper.Pager(page, size, defaultSize, totalRecords, action, null, pageName, routeValues, pageSizeName,null);
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        /// <param name="pageSizeName">每页大小的名称</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string pageName, RouteValueDictionary routeValues, string pageSizeName)
        {
            return htmlHelper.Pager(page, size, defaultSize, totalRecords, null, null, pageName, routeValues, pageSizeName,null);
        }
        
        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="action">ActionName</param>
        /// <param name="controller">ControllerName</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string action, string controller, string pageName, RouteValueDictionary routeValues)
        {
            return htmlHelper.Pager(page, size,defaultSize, totalRecords, action, controller, pageName, routeValues,null,null);
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="action">ActionName</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string action, string pageName, RouteValueDictionary routeValues)
        {
            return htmlHelper.Pager(page, size, defaultSize, totalRecords, action, null, pageName, routeValues);
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="size">页的行数</param>
        /// <param name="defaultSize">默认的每页大小</param>
        /// <param name="totalRecords">总行数</param>
        /// <param name="pageName">分页参数的名称</param>
        /// <param name="routeValues">生成Url时所带的参数</param>
        public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int? page, int? size, int defaultSize, int totalRecords, string pageName, RouteValueDictionary routeValues)
        {
            return htmlHelper.Pager(page, size, defaultSize, totalRecords, null, null, pageName, routeValues);
        }
        
        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string action, string controller, object htmlAtt)
        {
            var str=helper.ActionLink(linkText, action, controller, null, htmlAtt);
            return str;
        }

        /// <summary>
        /// 自定义HtmlHelper Label方法，解决for属性和国际化字符串不能同时解决的问题 
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="DisplayName"></param>
        /// <returns></returns>
        public static MvcHtmlString Label<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string DisplayName)
        {

            string modelName = ExpressionHelper.GetExpressionText(expression);

            TagBuilder tagBuilder = new TagBuilder("label");

            tagBuilder.Attributes.Add("for", modelName);

            tagBuilder.InnerHtml = DisplayName;

            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));

        }

        /// <summary>
        /// 自定义HtmlHelper 序列化Model
        /// </summary>
        public static MvcHtmlString SerializableFor<TModel,TValue>(this HtmlHelper<TModel> htmlHelper,Expression<Func<TModel, TValue>> expression)
        {
            string modelName = ExpressionHelper.GetExpressionText(expression);

            var value=ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

            return Serializable(htmlHelper, modelName, value.Model);
        }
        
        /// <summary>
        /// 自定义HtmlHelper 序列化Model
        /// </summary>
        public static MvcHtmlString Serializable(this HtmlHelper htmlHelper,string modelName, object value)
        {


            var sl = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            var sm = new System.IO.MemoryStream();
            sl.Serialize(sm, value);

            var bytes = sm.ToArray();

            string str = Convert.ToBase64String(bytes);

            sm.Dispose();


            TagBuilder tagBuilder = new TagBuilder("input");

            tagBuilder.Attributes.Add("type", "hidden");
            tagBuilder.Attributes.Add("name", modelName);
            tagBuilder.Attributes.Add("id", modelName);
            tagBuilder.Attributes.Add("value", str);


            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
        
        }


        //
        // 摘要:
        //     禁用通过Model定义的客户端脚本验证。
        public static void DisableClientValidation(this HtmlHelper htmlHelper)
        {
            htmlHelper.ViewContext.ClientValidationEnabled = false;
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper,string actionName,string controllerName, object htmlAttributes, object routeValues)
        {
            return htmlHelper.BeginForm(actionName, controllerName, routeValues,FormMethod.Post,htmlAttributes);
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper,string actionName, object htmlAttributes, object routeValues)
        {
            string controllerName = htmlHelper.ViewContext.RouteData.Values["controller"].ToString();
            return htmlHelper.BeginForm(actionName, controllerName, htmlAttributes, routeValues);
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper, object htmlAttributes, object routeValues)
        {
            string col = htmlHelper.ViewContext.RouteData.Values["controller"].ToString();
            string act=htmlHelper.ViewContext.RouteData.Values["action"].ToString();
            return htmlHelper.BeginForm(act, col, htmlAttributes, routeValues);
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
        {
            return htmlHelper.BeginForm(actionName, controllerName, routeValues, FormMethod.Post, htmlAttributes);
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
        {
            string controllerName = htmlHelper.ViewContext.RouteData.Values["controller"].ToString();
            return htmlHelper.BeginForm(actionName, controllerName, routeValues,htmlAttributes);
        }

        public static MvcForm BeginForm(this HtmlHelper htmlHelper, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
        {
            string col = htmlHelper.ViewContext.RouteData.Values["controller"].ToString();
            string act=htmlHelper.ViewContext.RouteData.Values["action"].ToString();
            return htmlHelper.BeginForm(act, col, routeValues, htmlAttributes);
        }


        /// <summary>
        /// 生成路由参数
        /// </summary>
        public static RouteValueDictionary Route(this UrlHelper helper,params object[] args)
        {
            var obj = new RouteValueDictionary();
            PastRoute(obj, string.Empty, args);
            return obj;
        }

        private static RouteValueDictionary PastRoute(RouteValueDictionary dic, string path,params object[] obj)
        {
            if (dic == null)
                throw new ArgumentNullException("dic");
            if (obj != null)
            {
                if (!string.IsNullOrEmpty(path))
                    path += ".";
                else
                    path = string.Empty;
                obj.Each(p =>
                {
                    foreach (ComponentModel.PropertyDescriptor item in System.ComponentModel.TypeDescriptor.GetProperties(p))
                    {
                        if (item.PropertyType.IsEnum || item.PropertyType.IsValueType || item.PropertyType == typeof(string))
                            dic.Add(path + item.Name, item.GetValue(p));
                        else
                            PastRoute(dic, path+item.Name, item.GetValue(p));
                    }
                });
            }
            return dic;
        }
    }

}